load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
load("//bazel:defs.bzl", "rust_ic_test")

BUILD_DEPENDENCIES = []

LIB_DEPENDENCIES = [
    # Keep sorted.
    "//packages/ic-ed25519",
    "//packages/ic-error-types",
    "//packages/icrc-ledger-types",
    "//packages/pocket-ic:pocket-ic",
    "//rs/bitcoin/adapter",
    "//rs/boundary_node/ic_boundary",
    "//rs/canister_sandbox:backend_lib",
    "//rs/config",
    "//rs/crypto/iccsa",
    "//rs/crypto/sha2",
    "//rs/crypto/utils/threshold_sig_der",
    "//rs/http_endpoints/nns_delegation_manager",
    "//rs/http_endpoints/public",
    "//rs/https_outcalls/adapter:adapter_with_http",
    "//rs/https_outcalls/client",
    "//rs/https_outcalls/service",
    "//rs/interfaces",
    "//rs/interfaces/adapter_client",
    "//rs/interfaces/registry",
    "//rs/interfaces/state_manager",
    "//rs/ledger_suite/icp:icp_ledger",
    "//rs/ledger_suite/icp/index:ic-icp-index",
    "//rs/ledger_suite/icrc1/index-ng",
    "//rs/limits",
    "//rs/monitoring/logger",
    "//rs/monitoring/metrics",
    "//rs/nervous_system/common",
    "//rs/nns/cmc",
    "//rs/nns/common",
    "//rs/nns/constants",
    "//rs/nns/governance/api",
    "//rs/nns/governance/init",
    "//rs/nns/handlers/root/impl:root",
    "//rs/nns/sns-wasm",
    "//rs/protobuf",
    "//rs/registry/canister",
    "//rs/registry/canister/api",
    "//rs/registry/client",
    "//rs/registry/helpers",
    "//rs/registry/keys",
    "//rs/registry/nns_data_provider",
    "//rs/registry/proto_data_provider",
    "//rs/registry/routing_table",
    "//rs/registry/subnet_type",
    "//rs/registry/transport",
    "//rs/replicated_state",
    "//rs/state_machine_tests",
    "//rs/state_manager",
    "//rs/test_utilities",
    "//rs/test_utilities/registry",
    "//rs/types/management_canister_types",
    "//rs/types/types",
    "//rs/utils/thread",
    "//rs/validator/ingress_message",
    "@crate_index//:aide",
    "@crate_index//:askama",
    "@crate_index//:axum",
    "@crate_index//:axum-extra",
    "@crate_index//:axum-server",
    "@crate_index//:backoff",
    "@crate_index//:base64",
    "@crate_index//:bitcoin",
    "@crate_index//:bytes",
    "@crate_index//:candid",
    "@crate_index//:clap",
    "@crate_index//:ctrlc",
    "@crate_index//:flate2",
    "@crate_index//:form_urlencoded",
    "@crate_index//:fqdn",
    "@crate_index//:futures",
    "@crate_index//:hex",
    "@crate_index//:http",
    "@crate_index//:http-body-util",
    "@crate_index//:hyper",
    "@crate_index//:hyper-util",
    "@crate_index//:ic-agent",
    "@crate_index//:ic-bn-lib-common",
    "@crate_index//:ic-btc-interface",
    "@crate_index//:ic-cdk",
    "@crate_index//:ic-doge-interface",
    "@crate_index//:ic-gateway",
    "@crate_index//:ic-utils",
    "@crate_index//:itertools",
    "@crate_index//:libc",
    "@crate_index//:rand",
    "@crate_index//:reqwest",
    "@crate_index//:serde",
    "@crate_index//:serde_cbor",
    "@crate_index//:serde_json",
    "@crate_index//:slog",
    "@crate_index//:strum",
    "@crate_index//:tempfile",
    "@crate_index//:time",
    "@crate_index//:tokio",
    "@crate_index//:tokio-util",
    "@crate_index//:tonic",
    "@crate_index//:tower",
    "@crate_index//:tower-http",
    "@crate_index//:tracing",
    "@crate_index//:tracing-appender",
    "@crate_index//:tracing-subscriber",
    "@crate_index//:uuid",
    "@crate_index//:wat",
]

TEST_DEPENDENCIES = [
    # Keep sorted.
    "//packages/pocket-ic:pocket-ic",
    "//rs/bitcoin/adapter/test_utils",
    "//rs/config",
    "//rs/interfaces/registry",
    "//rs/nns/constants",
    "//rs/registry/canister",
    "//rs/registry/proto_data_provider",
    "//rs/registry/routing_table",
    "//rs/registry/transport",
    "//rs/types/management_canister_types",
    "//rs/types/types",
    "@crate_index//:bitcoin",
    "@crate_index//:candid",
    "@crate_index//:candid_parser",
    "@crate_index//:flate2",
    "@crate_index//:hex",
    "@crate_index//:ic-agent",
    "@crate_index//:ic-btc-interface",
    "@crate_index//:ic-cdk",
    "@crate_index//:ic-doge-interface",
    "@crate_index//:ic-gateway",
    "@crate_index//:ic-utils",
    "@crate_index//:nix",
    "@crate_index//:prometheus",
    "@crate_index//:rcgen",
    "@crate_index//:reqwest",
    "@crate_index//:rustls",
    "@crate_index//:serde",
    "@crate_index//:serde_json",
    "@crate_index//:slog",
    "@crate_index//:tempfile",
    "@crate_index//:tokio",
    "@crate_index//:walrus",
    "@crate_index//:wat",
]

MACRO_DEPENDENCIES = [
    "@crate_index//:async-trait",
]

ALIASES = {}

EXTERNAL_CANISTER_DATA = [
    "@mainnet_canisters//:cycles_ledger.wasm.gz",
    "@mainnet_canisters//:internet_identity_test.wasm.gz",
    "@mainnet_canisters//:sns_aggregator_test.wasm.gz",
    "@mainnet_canisters//:nns_dapp_test.wasm.gz",
    "@mainnet_canisters//:bitcoin_testnet.wasm.gz",
    "@mainnet_canisters//:dogecoin.wasm.gz",
]

EXTERNAL_CANISTER_ENV = {
    "CYCLES_LEDGER_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:cycles_ledger.wasm.gz)",
    "INTERNET_IDENTITY_TEST_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:internet_identity_test.wasm.gz)",
    "SNS_AGGREGATOR_TEST_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns_aggregator_test.wasm.gz)",
    "NNS_DAPP_TEST_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:nns_dapp_test.wasm.gz)",
    "BITCOIN_TESTNET_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:bitcoin_testnet.wasm.gz)",
    "DOGECOIN_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:dogecoin.wasm.gz)",
}

HEAD_NNS_CANISTER_DATA = [
    "//rs/ledger_suite/icrc1/index-ng:index_ng_canister_u256",
    "//rs/ledger_suite/icrc1/archive:archive_canister",
    "//rs/ledger_suite/icrc1/index-ng:index_ng_canister",
    "//rs/ledger_suite/icrc1/ledger:ledger_canister",
    "//rs/ledger_suite/icp/index:ic-icp-index-canister",
    "//rs/ledger_suite/icp/ledger:ledger-canister-wasm",
    "//rs/nns/cmc:cycles-minting-canister",
    "//rs/registry/canister:registry-canister",
    "//rs/nns/handlers/root/impl:root-canister",
    "//rs/nns/sns-wasm:sns-wasm-canister",
    "//rs/sns/governance:sns-governance-canister-test",
    "//rs/sns/root:sns-root-canister",
    "//rs/sns/swap:sns-swap-canister",
    "//rs/nns/governance:governance-canister-test",
    "//rs/migration_canister:migration-canister",
]

HEAD_NNS_CANISTER_ENV = {
    "REGISTRY_CANISTER_WASM_PATH": "$(location //rs/registry/canister:registry-canister)",
    "CYCLES_MINTING_CANISTER_WASM_PATH": "$(location //rs/nns/cmc:cycles-minting-canister)",
    "ICP_LEDGER_CANISTER_WASM_PATH": "$(location //rs/ledger_suite/icp/ledger:ledger-canister-wasm)",
    "ICP_INDEX_CANISTER_WASM_PATH": "$(location //rs/ledger_suite/icp/index:ic-icp-index-canister)",
    "CYCLES_LEDGER_INDEX_CANISTER_WASM_PATH": "$(location //rs/ledger_suite/icrc1/index-ng:index_ng_canister_u256)",
    "GOVERNANCE_TEST_CANISTER_WASM_PATH": "$(location //rs/nns/governance:governance-canister-test)",
    "ROOT_CANISTER_WASM_PATH": "$(location //rs/nns/handlers/root/impl:root-canister)",
    "SNS_WASM_CANISTER_WASM_PATH": "$(location //rs/nns/sns-wasm:sns-wasm-canister)",
    "SNS_ROOT_CANISTER_WASM_PATH": "$(location //rs/sns/root:sns-root-canister)",
    "SNS_GOVERNANCE_CANISTER_WASM_PATH": "$(location //rs/sns/governance:sns-governance-canister-test)",
    "SNS_SWAP_CANISTER_WASM_PATH": "$(location //rs/sns/swap:sns-swap-canister)",
    "SNS_LEDGER_CANISTER_WASM_PATH": "$(location //rs/ledger_suite/icrc1/ledger:ledger_canister)",
    "SNS_LEDGER_ARCHIVE_CANISTER_WASM_PATH": "$(location //rs/ledger_suite/icrc1/archive:archive_canister)",
    "SNS_LEDGER_INDEX_CANISTER_WASM_PATH": "$(location //rs/ledger_suite/icrc1/index-ng:index_ng_canister)",
    "MIGRATION_CANISTER_WASM_PATH": "$(location //rs/migration_canister:migration-canister)",
}

MAINNET_NNS_CANISTER_DATA = [
    "@mainnet_canisters//:cycles_ledger_index.wasm.gz",
    "@mainnet_canisters//:sns_archive.wasm.gz",
    "@mainnet_canisters//:sns_index.wasm.gz",
    "@mainnet_canisters//:sns_ledger.wasm.gz",
    "@mainnet_canisters//:index.wasm.gz",
    "@mainnet_canisters//:ledger.wasm.gz",
    "@mainnet_canisters//:cycles-minting.wasm.gz",
    "@mainnet_canisters//:registry.wasm.gz",
    "@mainnet_canisters//:root.wasm.gz",
    "@mainnet_canisters//:sns-wasm.wasm.gz",
    "@mainnet_canisters//:sns_governance.wasm.gz",
    "@mainnet_canisters//:sns_root.wasm.gz",
    "@mainnet_canisters//:swap.wasm.gz",
    "@mainnet_canisters//:governance-canister_test.wasm.gz",
    "//rs/migration_canister:migration-canister",  # the migration canister is not yet deployed to the ICP mainnet
]

MAINNET_NNS_CANISTER_ENV = {
    "REGISTRY_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:registry.wasm.gz)",
    "CYCLES_MINTING_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:cycles-minting.wasm.gz)",
    "ICP_LEDGER_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:ledger.wasm.gz)",
    "ICP_INDEX_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:index.wasm.gz)",
    "CYCLES_LEDGER_INDEX_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:cycles_ledger_index.wasm.gz)",
    "GOVERNANCE_TEST_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:governance-canister_test.wasm.gz)",
    "ROOT_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:root.wasm.gz)",
    "SNS_WASM_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns-wasm.wasm.gz)",
    "SNS_ROOT_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns_root.wasm.gz)",
    "SNS_GOVERNANCE_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns_governance.wasm.gz)",
    "SNS_SWAP_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:swap.wasm.gz)",
    "SNS_LEDGER_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns_ledger.wasm.gz)",
    "SNS_LEDGER_ARCHIVE_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns_archive.wasm.gz)",
    "SNS_LEDGER_INDEX_CANISTER_WASM_PATH": "$(location @mainnet_canisters//:sns_index.wasm.gz)",
    "MIGRATION_CANISTER_WASM_PATH": "$(location //rs/migration_canister:migration-canister)",
}

[
    cargo_build_script(
        name = "build_script" + name_suffix,
        srcs = ["build.rs"],
        aliases = ALIASES,
        build_script_env = EXTERNAL_CANISTER_ENV | nns_canister_env,
        data = EXTERNAL_CANISTER_DATA + nns_canister_data + [
            "templates/dashboard.html",
        ],
        deps = BUILD_DEPENDENCIES,
    )
    for (name_suffix, nns_canister_data, nns_canister_env) in [
        ("_head_nns", HEAD_NNS_CANISTER_DATA, HEAD_NNS_CANISTER_ENV),
        ("", MAINNET_NNS_CANISTER_DATA, MAINNET_NNS_CANISTER_ENV),
    ]
]

[
    rust_library(
        name = "pocket-ic-server-lib" + name_suffix,
        testonly = True,
        srcs = [
            "src/beta_features.rs",
            "src/external_canister_types.rs",
            "src/lib.rs",
            "src/pocket_ic.rs",
        ] + glob([
            "src/state_api/**/*.rs",
        ]),
        compile_data = EXTERNAL_CANISTER_DATA + nns_canister_data,
        crate_name = "pocket_ic_server",
        proc_macro_deps = MACRO_DEPENDENCIES,
        rustc_env = EXTERNAL_CANISTER_ENV | nns_canister_env,
        version = "11.0.0",
        deps = LIB_DEPENDENCIES + [":build_script"],
    )
    for (name_suffix, nns_canister_data, nns_canister_env) in [
        ("-head-nns", HEAD_NNS_CANISTER_DATA, HEAD_NNS_CANISTER_ENV),
        ("", MAINNET_NNS_CANISTER_DATA, MAINNET_NNS_CANISTER_ENV),
    ]
]

[
    rust_binary(
        name = "pocket-ic-server" + name_suffix,
        testonly = True,
        srcs = ["src/main.rs"],
        compile_data = ["src/mainnet_routing_table.json"],  # generated by running `ic-admin get-routing-table --json`
        proc_macro_deps = MACRO_DEPENDENCIES,
        # TODO: restrict the visibility
        visibility = ["//visibility:public"],
        deps = LIB_DEPENDENCIES + [
            ":pocket-ic-server-lib" + name_suffix,
            "//rs/canister_sandbox:build_script",
            "//rs/registry/admin",
            "@crate_index//:url",
        ],
    )
    for name_suffix in [
        "-head-nns",
        "",
    ]
]

rust_ic_test(
    name = "pocket-ic-server-lib-test",
    crate = ":pocket-ic-server-lib",
    proc_macro_deps = MACRO_DEPENDENCIES,
    deps = TEST_DEPENDENCIES,
)

rust_test(
    name = "external_types_tests",
    size = "small",
    srcs = ["tests/external_types_tests.rs"],
    data = EXTERNAL_CANISTER_DATA + MAINNET_NNS_CANISTER_DATA,
    rustc_env = EXTERNAL_CANISTER_ENV | MAINNET_NNS_CANISTER_ENV,
    # this test is manual to not block automatic PR merge
    # bumping mainnet canister versions
    # from which the external types are derived
    tags = ["pocketic_tests_nightly"],
    deps = [":pocket-ic-server-lib"] + TEST_DEPENDENCIES,
)

[
    rust_test(
        name = name,
        size = "medium",
        timeout = "long",
        srcs = [
            "tests/common.rs",
            "tests/" + name + ".rs",
        ],
        aliases = {},
        data = [
            ":pocket-ic-server",
            "@ii_dev_canister//file",
            "@mozilla_root_ca_store//file",
        ],
        env = {
            "RUST_TEST_THREADS": "2",
            "POCKET_IC_BIN": "$(rootpath :pocket-ic-server)",
            "II_WASM": "$(rootpath @ii_dev_canister//file)",
            "SSL_CERT_FILE": "$(rootpath @mozilla_root_ca_store//file)",
        },
        tags = [
            "cpu:8",
            # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed.
            # Failed to bind PocketIC server to address 127.0.0.1:0
            "requires-network",
            "test_all_platforms",
        ],
        deps = TEST_DEPENDENCIES,
    )
    for name in [
        "test",
        "gateway",
    ]
]

rust_test(
    name = "bitcoin_integration_tests",
    srcs = [
        "tests/bitcoin_integration_tests.rs",
    ],
    aliases = {},
    data = [
        ":pocket-ic-server",
        "//:bitcoind",
        "@bitcoin_example_canister//file",
        "@mozilla_root_ca_store//file",
    ],
    env = {
        "POCKET_IC_BIN": "$(rootpath :pocket-ic-server)",
        "BITCOIN_EXAMPLE_CANISTER_WASM": "$(rootpath @bitcoin_example_canister//file)",
        "BITCOIND_BIN": "$(rootpath //:bitcoind)",
        "SSL_CERT_FILE": "$(rootpath @mozilla_root_ca_store//file)",
    },
    tags = [
        "test_all_platforms",
    ],
    deps = TEST_DEPENDENCIES,
)

rust_test(
    name = "dogecoin_integration_tests",
    srcs = [
        "tests/dogecoin_integration_tests.rs",
    ],
    aliases = {},
    data = [
        ":pocket-ic-server",
        "//:dogecoind",
        "@dogecoin_example_canister//file",
        "@mozilla_root_ca_store//file",
    ],
    env = {
        "POCKET_IC_BIN": "$(rootpath :pocket-ic-server)",
        "DOGECOIN_EXAMPLE_CANISTER_WASM": "$(rootpath @dogecoin_example_canister//file)",
        "DOGECOIND_BIN": "$(rootpath //:dogecoind)",
        "SSL_CERT_FILE": "$(rootpath @mozilla_root_ca_store//file)",
    },
    tags = [],
    deps = TEST_DEPENDENCIES,
)
